import base64
from io import BytesIO
from docxtpl import DocxTemplate, InlineImage
import tempfile
import os
from docx.shared import Mm
from typing import Generator
import requests



def render_docx_template(template_path: str, data: dict) -> str:
    """
    渲染 docx 模板并返回临时文件路径
    """
    doc = DocxTemplate(template_path)

    parsed_data = parse_context(doc, data)

    try:
        doc.render(parsed_data)
    except Exception as e:
        raise ValueError(f"Error rendering template: {str(e)}")

    tmp_file = tempfile.NamedTemporaryFile(delete=False, suffix=".docx")
    tmp_file_path = tmp_file.name
    tmp_file.close()

    try:
        doc.save(tmp_file_path)
        return tmp_file_path
    except Exception as e:
        if os.path.exists(tmp_file_path):
            os.remove(tmp_file_path)
        raise RuntimeError(f"Error saving rendered file: {str(e)}")


def get_file_stream_and_cleanup(file_path: str) -> Generator[bytes, None, None]:
    """
    边读边传输 Word 文件，并在读完后删除文件
    """
    with open(file_path, "rb") as f:
        yield from f
    os.remove(file_path)


def build_image(doc, image_info: dict) -> InlineImage | None:
    """
    根据 image_info 创建 InlineImage 实例
    """

    path = image_info.get("image_path", "")
    width = Mm(image_info.get("width_mm", 48))
    height = Mm(image_info.get("height_mm", 48))

    if not path:
        return None

    if path.startswith("data:image"):  # base64
        try:
            header, b64data = path.split(",", 1)
            image_bytes = BytesIO(base64.b64decode(b64data))
            return InlineImage(doc, image_bytes, width, height)
        except Exception:
            return None

    elif path.startswith("http"):  # 网络图片
        try:
            res = requests.get(path)
            if res.status_code == 200:
                return InlineImage(doc, BytesIO(res.content), width, height)
        except Exception:
            return None

    else:  # 本地路径
        try:
            return InlineImage(doc, path, width, height)
        except Exception:
            return None


def parse_context(doc, data: dict):
    if isinstance(data, dict):
        result = {}
        for k, v in data.items():
            if isinstance(v, dict) and "image_path" in v:
                result[k] = build_image(doc, v)
            else:
                result[k] = parse_context(doc, v)
        return result
    elif isinstance(data, list):
        return [parse_context(doc, item) for item in data]
    else:
        return data
